package cn.xie.ai.rag.knowledge.trigger.http;

import cn.xie.ai.rag.knowledge.api.IRagService;
import cn.xie.ai.rag.knowledge.api.response.Response;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.springframework.ai.document.Document;
import org.springframework.ai.ollama.OllamaChatClient;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.PgVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.core.io.PathResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: xiaoxie
 * create: 2025-06-02 20:49
 * @BelongsProject: ai-rag-knowledge
 * @BelongsPackage: cn.xie.ai.rag.knowledge.trigger.http
 * description: Rag
 */
@Slf4j
@RestController()
@CrossOrigin("*")
@RequestMapping("/api/v1/rag/")

public class RagController implements IRagService {
    @Resource
    private OllamaChatClient ollamaChatClient;
    @Resource
    private TokenTextSplitter tokenTextSplitter;

    @Resource
    private PgVectorStore pgVectorStore;
    @Resource
    private RedissonClient redissonClient;


    @RequestMapping(value = "query_rag_tag_list", method = RequestMethod.GET)
    @Override
    public Response<List<String>> queryRagTagList() {
        RList<String> elements = redissonClient.getList("ragTag");
        return Response.<List<String>>builder()
                .code("0000")
                .msg("调用成功")
                .data(elements)
                .build();

    }

    @RequestMapping(value = "file/upload", method = RequestMethod.POST, headers = "content-type=multipart/form-data")
    @Override
    public Response<String> uploadRagTag(@RequestParam("ragTag") String ragTag, @RequestParam("file") List<MultipartFile> files) {
        log.info("上传知识库开始 {}", ragTag);
        for (MultipartFile file : files) {
            TikaDocumentReader documentReader = new TikaDocumentReader(file.getResource());
            List<Document> documents = documentReader.get();
            List<Document> documentSplitterList = tokenTextSplitter.apply(documents);

            documents.forEach(doc -> doc.getMetadata().put("knowledge", ragTag));
            documentSplitterList.forEach(doc -> doc.getMetadata().put("knowledge", ragTag));

            pgVectorStore.accept(documentSplitterList);

            RList<String> elements = redissonClient.getList("ragTag");
            if (!elements.contains(ragTag)){
                elements.add(ragTag);
            }
        }

        log.info("上传知识库完成 {}", ragTag);
        return Response.<String>builder().code("0000").msg("调用成功").build();
    }

    @RequestMapping(value = "delete", method = RequestMethod.GET)
    @Override
    public Response<Boolean> deleteRagTag(String tags) {
        log.info("删除知识库标签开始，标签：{}", tags);

        // 从Redis中删除标签
        RList<String> ragTagList = redissonClient.getList("ragTag");
        boolean isRemovedFromRedis = ragTagList.remove(tags);

        if (isRemovedFromRedis) {
            log.info("成功从Redis中删除标签：{}", tags);
        } else {
            log.warn("标签：{} 在Redis中不存在，无法删除", tags);
        }

        // 从向量存储中删除与该标签相关的文档
        // 从向量存储中删除与该标签相关的所有文档
        boolean isRemovedFromVectorStore = deleteDocumentsByTag(tags);

        if (isRemovedFromVectorStore) {
            log.info("成功从向量存储中删除与标签：{} 相关的文档", tags);
        } else {
            log.warn("从向量存储中删除与标签：{} 相关的文档时失败", tags);
        }

        // 判断是否全部删除成功
        boolean isSuccess = isRemovedFromRedis && isRemovedFromVectorStore;

        return Response.<Boolean>builder()
                .code("0000")
                .msg("调用成功")
                .data(isSuccess)
                .build();
    }
    private boolean deleteDocumentsByTag(String tag) {
        // 假设 PgVectorStore 提供了根据标签删除文档的方法
        // 这里需要根据实际的 PgVectorStore 实现来调整代码
        // 以下是一个示例实现，可能需要根据实际情况修改

        // 构建查询条件，查找所有 metadata 中包含指定标签的文档
        SearchRequest searchRequest = SearchRequest.query("")
                .withFilterExpression("knowledge == '" + tag + "'");

        // 获取所有匹配的文档
        List<Document> documentsToDelete = pgVectorStore.similaritySearch(searchRequest);

        if (documentsToDelete.isEmpty()) {
            log.warn("向量存储中没有找到与标签：{} 相关的文档，无法删除", tag);
            return false;
        }

        // 获取所有文档的唯一标识符（例如文档的 ID）
        List<String> documentIds = documentsToDelete.stream()
                .map(Document::getId)
                .collect(Collectors.toList());

        // 删除文档
        Optional<Boolean> isDeleted = pgVectorStore.delete(documentIds);

        if (isDeleted.get()) {
            log.info("成功从向量存储中删除与标签：{} 相关的文档，共 {} 个", tag, documentIds.size());
        } else {
            log.warn("从向量存储中删除与标签：{} 相关的文档时失败", tag);
        }

        return isDeleted.get();
    }

    @RequestMapping(value = "analyze_git_repository", method = RequestMethod.POST)
    @Override
    public Response<String> analyzeGitRepository(@RequestParam String repoUrl, @RequestParam String userName, @RequestParam String token) throws Exception {
        String localPath = "./git-cloned-repo";
        String repoProjectName = extractProjectName(repoUrl);
        log.info("克隆路径：{}", new File(localPath).getAbsolutePath());

        FileUtils.deleteDirectory(new File(localPath));

        Git git = Git.cloneRepository()
                .setURI(repoUrl)
                .setDirectory(new File(localPath))
                .setCredentialsProvider(new UsernamePasswordCredentialsProvider(userName, token))
                .call();

        Files.walkFileTree(Paths.get(localPath), new SimpleFileVisitor<>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                log.info("{} 遍历解析路径，上传知识库:{}", repoProjectName, file.getFileName());
                try {
                    TikaDocumentReader reader = new TikaDocumentReader(new PathResource(file));
                    List<Document> documents = reader.get();
                    List<Document> documentSplitterList = tokenTextSplitter.apply(documents);

                    documents.forEach(doc -> doc.getMetadata().put("knowledge", repoProjectName));

                    documentSplitterList.forEach(doc -> doc.getMetadata().put("knowledge", repoProjectName));

                    pgVectorStore.accept(documentSplitterList);
                } catch (Exception e) {
                    log.error("遍历解析路径，上传知识库失败:{}", file.getFileName());
                }

                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                log.info("Failed to access file: {} - {}", file.toString(), exc.getMessage());
                return FileVisitResult.CONTINUE;
            }
        });

        FileUtils.deleteDirectory(new File(localPath));

        RList<String> elements = redissonClient.getList("ragTag");
        if (!elements.contains(repoProjectName)) {
            elements.add(repoProjectName);
        }

        git.close();

        log.info("遍历解析路径，上传完成:{}", repoUrl);

        return Response.<String>builder().code("0000").msg("调用成功").build();
    }

    private String extractProjectName(String repoUrl) {
        String[] parts = repoUrl.split("/");
        String projectNameWithGit = parts[parts.length - 1];
        return projectNameWithGit.replace(".git", "");
    }


}
